//
// Created by tang on 2022/3/30.
//

#include "app.hpp"
#include "log.hpp"

#include <ctime>

#include <pigpio.h>

static double get_time() {
    struct timespec now{};
    clock_gettime(CLOCK_MONOTONIC, &now);
    return static_cast<double >(now.tv_sec) + static_cast<double >(now.tv_nsec) * 0.000000001;
}

static void thr_sleep_ms(int64_t ms)
{
    if (ms <= 0)
        return;
    struct timespec ts{};
    ts.tv_sec = ms / 1000;
    ts.tv_nsec = (ms % 1000) * 1000 * 1000;
    nanosleep(&ts, nullptr);
}

App::App(): running_flag(true) {
    LOG_D("APP Initializing ...");
    Init();
}

App::~App() {
    gpioTerminate();
    LOG_D("APP Destroying ...");
}

void App::Run() {
    LOG_D("APP Running ...");
    double current_time = get_time();
    while (running_flag.load()) {
        //
        double new_time = get_time();
        for (auto &ptr : components) {
            ptr->OnUpdate(new_time - current_time);
        }
        current_time = new_time;
        thr_sleep_ms(static_cast<int64_t>(125.0 - (new_time - current_time) * 1000));
    }
}

void App::RegisterSystemComponent(SystemComponentPtr component) {
    components.emplace_back(move(component));
}

void App::Quit() {
    running_flag.store(false);
}

void App::Init() {
    // 初始化 GPIO 库
    gpioInitialise();
    LOG_I("pigpio init, version %d", gpioVersion());
}
